#include <stdint.h>
#include "CIM_nice.h"
#include <hbird_sdk_soc.h>
#define ROW_NUM 576
#define I1  484
#define H1  118
#define O1  10


void mlp_pre_bitwise_read(uint8_t*img){
		int8_t zeros[576]={0};
		NICE_push((int)zeros ,576);  //clear buffer

		printf("\n**********show img*******************\n");
	     for(int i=0*I1;i<I1*1;i++){
				printf("%d",img[i]);
				if((i+1)%22==0){
					printf("\n");
				}
			}
		int8_t out_re1[128] = {0};

//**********************1. nice input config*******************
	    uint32_t push_row_index,push_data_num,save_index,save_num;
		uint32_t mvm_row_start,mvm_row_num,mvm_col_start,mvm_col_num;
	    push_row_index = 4*0;	push_data_num = 484;  // x4
	    save_index = 0;		 	save_num = 92;	// x4
	    mvm_row_start = 0;   	mvm_row_num   = 484;
	    mvm_col_start = 0;   	mvm_col_num   = 92;
	    uint32_t push_rs2,save_rs2,mvm_rs1,mvm_rs2;
	    push_rs2  = push_row_index << 11| push_data_num;
	    mvm_rs2   = mvm_row_start<<11 	| mvm_col_start;
	    mvm_rs1   = mvm_row_num<< 16    | mvm_col_num;
	    save_rs2  = save_index<< 11 	| save_num;
//***********************2. first layer input data********************
	    printf("first layer  : \n");
	    uint32_t adc_range=0;
	    uint32_t out_shift=1;

	    uint32_t config = 1<<23|127<<16 | 1 << 8|0;
	    unsigned int begin_cycle,tmp_cycle;
	    NICE_config(config,0);
	    begin_cycle = __get_rv_cycle();
		NICE_push((int)img ,push_rs2);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
		printf("push cycle: %d \n" ,tmp_cycle);

		begin_cycle = __get_rv_cycle();
		NICE_mvm(mvm_rs1,mvm_rs2);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
		printf("mvm cycle: %d \n" ,tmp_cycle);

		begin_cycle = __get_rv_cycle();
		NICE_save((int)out_re1,save_rs2);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
		printf("save cycle: %d \n" ,tmp_cycle);
		for(int i= 0;i<10;i++){
			printf("%6d ",out_re1[i]);
				if( (i+1)%10==0 ) printf("\n");
		}
		//printf("%8x \n",tmp_re);
//		for(int i= 0;i<100;i++){
//			printf("%6d ",out_re1[i]);
//				if( (i+1)%10==0 ) printf("\n");
//		}
//		printf("\n%6d %6d %6d %6d %6d %6d \n",out_re1[90],out_re1[91],out_re1[92],out_re1[93],out_re1[94],out_re1[95]);
		//printf("\n");
//*********************3.relu**********************************
		printf("\nbegin relu   : \n");
		for(int i= 0;i<128;i++){
			if(out_re1[i]<0) {
	//			printf("%d   ",out_re1[i]);
				out_re1[i]=0;
			}
			if(i<10){
				printf("%6d ",out_re1[i] );
				if((i+1)%10==0){
					printf("\n");
				}
			}
		}

		printf("\nsecond layer : \n");
//*********************4. second layer input data*****************
		int8_t out_re2[30] ;

		push_rs2 = 484<<11  | 92; 	//index,num
		mvm_rs2  = 484<<11  | (92);	//row_start,col_start
		mvm_rs1  = 92 <<16  | 10;	//row_num,col_num
		save_rs2 = (92)<<11 | 12;	//index,num

		NICE_push((int)zeros ,576);

		config = 1<<23|127<<16 | 3 << 8|0;
		NICE_config(config,0);
		begin_cycle = __get_rv_cycle();
		NICE_push((int)out_re1 ,push_rs2);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
		printf("push cycle: %d \n" ,tmp_cycle);


		begin_cycle = __get_rv_cycle();
		NICE_mvm(mvm_rs1,mvm_rs2);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
		printf("mvm2 cycle: %d \n" ,tmp_cycle);


		begin_cycle = __get_rv_cycle();
		NICE_save((int)out_re2,save_rs2);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
		printf("save cycle: %d \n" ,tmp_cycle);

		//*********************5. softmax ****************************
		int max=-65535;
		uint8_t max_index;
		for(int i = 0 ;i <10;i++){
			if(out_re2[i]>max){
				max = out_re2[i];
				max_index = i;
			}
			printf("%6d ",out_re2[i]);
		}
		printf("\npredict num = %d\n",max_index);
}


void mlp_pre_bitwise(uint8_t*img){
		int8_t zeros[576]={0};
		NICE_push((int)zeros ,576);  //clear buffer

//		printf("\n**********show img*******************\n");
//	     for(int i=0*I1;i<I1*1;i++){
//				printf("%d",img[i]);
//				if((i+1)%22==0){
//					printf("\n");
//				}
//			}

	     printf("\n**********show img*******************\n");
	     	     for(int i=0*I1;i<I1*1;i++){
	     	    	 	if(img[i]){
	     	    	 		printf("%c%c",'1',' ');
	     	    	 	}else{
	     	    	 		printf("%c%c",'-',' ');
	     	    	 	}

	     				if((i+1)%22==0){
	     					printf("\n");
	     				}
	     			}



		int8_t out_re1[128] = {0};

//**********************1. nice input config*******************
	    uint32_t push_row_index,push_data_num,save_index,save_num;
		uint32_t mvm_row_start,mvm_row_num,mvm_col_start,mvm_col_num;
	    push_row_index = 4*0;	push_data_num = 484;  // x4
	    save_index = 0;		 	save_num = 92;	// x4
	    mvm_row_start = 0;   	mvm_row_num   = 484;
	    mvm_col_start = 0;   	mvm_col_num   = 92;
	    uint32_t push_rs2,save_rs2,mvm_rs1,mvm_rs2;
	    push_rs2  = push_row_index << 11| push_data_num;
	    mvm_rs2   = mvm_row_start<<11 	| mvm_col_start;
	    mvm_rs1   = mvm_row_num<< 16    | mvm_col_num;
	    save_rs2  = save_index<< 11 	| save_num;
//***********************2. first layer input data********************
	    printf("first layer  : \n");
	    uint32_t adc_range=0;
	    uint32_t out_shift=1;

	    uint32_t config = 0<<23|1<<16 | 0 << 8|0;
	    unsigned int begin_cycle,tmp_cycle;
	    NICE_config(config,0);
	    begin_cycle = __get_rv_cycle();
		NICE_push((int)img ,push_rs2);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
		printf("push cycle: %d \n" ,tmp_cycle);

		begin_cycle = __get_rv_cycle();
		NICE_mvm(mvm_rs1,mvm_rs2);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
		printf("mvm cycle: %d \n" ,tmp_cycle);

		begin_cycle = __get_rv_cycle();
		NICE_save((int)out_re1,save_rs2);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
		printf("save cycle: %d \n" ,tmp_cycle);
		for(int i= 0;i<92;i++){
			printf("%6d ",out_re1[i]);
				if( (i+1)%10==0 ) printf("\n");
		}
		//printf("%8x \n",tmp_re);
//		for(int i= 0;i<100;i++){
//			printf("%6d ",out_re1[i]);
//				if( (i+1)%10==0 ) printf("\n");
//		}
//		printf("\n%6d %6d %6d %6d %6d %6d \n",out_re1[90],out_re1[91],out_re1[92],out_re1[93],out_re1[94],out_re1[95]);
		//printf("\n");
//*********************3.relu**********************************
		printf("\nbegin relu   : \n");
		for(int i= 0;i<128;i++){
			if(out_re1[i]<0) {
	//			printf("%d   ",out_re1[i]);
				out_re1[i]=0;
			}
//			if(i<10){
//				printf("%6d ",out_re1[i] );
//				if((i+1)%10==0){
//					printf("\n");
//				}
//			}
		}

		printf("\nsecond layer : \n");
//*********************4. second layer input data*****************
		int8_t out_re2[30] ;

		push_rs2 = 484<<11  | 92; 	//index,num
		mvm_rs2  = 484<<11  | (92);	//row_start,col_start
		mvm_rs1  = 92 <<16  | 10;	//row_num,col_num
		save_rs2 = (92)<<11 | 12;	//index,num

		NICE_push((int)zeros ,576);

		config = 0<<23|8<<16 | 0 << 8|0;
		NICE_config(config,0);
		begin_cycle = __get_rv_cycle();
		NICE_push((int)out_re1 ,push_rs2);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
		printf("push cycle: %d \n" ,tmp_cycle);


		begin_cycle = __get_rv_cycle();
		NICE_mvm(mvm_rs1,mvm_rs2);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
		printf("mvm2 cycle: %d \n" ,tmp_cycle);


		begin_cycle = __get_rv_cycle();
		NICE_save((int)out_re2,save_rs2);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
		printf("save cycle: %d \n" ,tmp_cycle);

		//*********************5. softmax ****************************
		int max=-65535;
		uint8_t max_index;
		for(int i = 0 ;i <10;i++){
			if(out_re2[i]>max){
				max = out_re2[i];
				max_index = i;
			}
			printf("%6d ",out_re2[i]);
		}
		printf("\npredict num = %d\n",max_index);
}



int printmat(int8_t* img, int row, int col){
	for(int i=0;i<row;i++){
		for(int j=0;j<col;j++){
			if(j==0){
				printf("\n");
			}
			printf("%d,",img[i*col+j]);
		}
	}
	printf("\n");
}

void mvm(int8_t* input, int in_len,
			int8_t* weight, int w_col,
			int8_t* output,int shift){
	int sum = 0;
	int tmp = 0;
	for(int col=0;col<w_col;col++){
		for(int row=0;row<in_len;row++){
			sum = sum + input[row] * weight[row*w_col + col];
		}
		tmp = sum>>shift;
		output[col] = tmp>127? 127:(tmp<-127?-127:tmp);
		sum = 0;
	}
}


int findmax(int8_t* input, int len){
	int max = input[0];
	int max_index = 0;
	for(int i=1;i<len;i++){
		if(max<input[i]){
			max=input[i];
			max_index = i;
		}
	}
	return max_index;
}

void relu(int8_t* input, int len){
	for(int i=0;i<len;i++){
		if(input[i]<0){
			input[i]=0;
		}
	}
}



void Get_1152(int16_t* push_data,uint32_t row_start,uint32_t row_end,uint16_t*data_1152){
	for(int i = 0 ;i < 72 ;i++){data_1152[i]=0;}
	uint16_t tmp = 0;
	for(int i = row_start ;i <= row_end ;i++){
	//	if (i < row_start){
	//		tmp = 0;
	//	}
	//	else if(i >= row_end) {
	//		tmp = 0;
	//	}
	//	if(i-row_start<5)printf("%d       ",push_data[i-row_start]);
		if(push_data[i-row_start]>0){
			push_data[i-row_start] -= 1;
			tmp = 1;
		}else if(push_data[i-row_start]<0){
			push_data[i-row_start] += 1;
			tmp = 2	;
		}else{
			push_data[i-row_start] = 0;
			tmp = 0;
		}
		data_1152[i/8] |= tmp <<((i%8)<<1);
	}
//	for(int j = 0 ; j < 8 ; j++)printf("%4x ", data_1152[j]);
//	printf("\n");
}

int16_t* matmul(int16_t *data, uint32_t data_len, uint32_t array_index, \
            uint32_t row_start_index, uint32_t col_start_index,\
            uint32_t row_end_index, uint32_t col_end_index)
{
    uint32_t config_info_push;
    uint32_t config_info_mvm_rs1;
    uint32_t config_info_mvm_rs2;
    uint32_t config_info_save;
    int16_t* re_tmp = (int16_t*)malloc((col_end_index - col_start_index + 1)*2);
	int16_t* re 	= (int16_t*)malloc((col_end_index - col_start_index + 1)*2);
    //config_info_push 	= array_index << 22 | row_start_index << 11 | data_len;
	config_info_push = 576;
	config_info_mvm_rs1 = col_end_index 	| row_end_index<<16	;
    config_info_mvm_rs2 = array_index << 22 | row_start_index << 11 | col_start_index;
    config_info_save 	= array_index << 22 | col_start_index << 11 | (col_end_index - col_start_index + 1);
	uint16_t input_register_1152[72] = {0};
	int i,j;
	uint16_t is_zero;

	unsigned int begin_cycle,tmp_cycle;

	for( i = 0; i < 255; i++){
		printf("%d \n",i);
		begin_cycle = __get_rv_cycle();
		Get_1152(data,row_start_index,row_end_index,input_register_1152);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
		printf("cycle: %d \n" ,tmp_cycle);

		begin_cycle = __get_rv_cycle();
	//	printf("%d %d %d %x\n",data[i],row_start_index,row_end_index,input_register_1152[i]);
		NICE_push((int)input_register_1152,config_info_push);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
	    printf("cycle: %d \n" ,tmp_cycle);

		begin_cycle = __get_rv_cycle();
		NICE_mvm(config_info_mvm_rs1,config_info_mvm_rs2);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
	    printf("cycle: %d \n" ,tmp_cycle);

		begin_cycle = __get_rv_cycle();
		NICE_save((int)re_tmp,config_info_save);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
	    printf("cycle: %d \n" ,tmp_cycle);

		if (i == 0){for (j=0; j <= col_end_index - col_start_index;j++){ re[j]  = re_tmp[j];}}
		else{   	for (j=0; j <= col_end_index - col_start_index;j++){ re[j] += re_tmp[j];}}
		//for(int k = 0 ;k<10;k++){printf("%d ",re_tmp[k]);}
		//printf("re \n");
		//for(int k = 0 ;k<10;k++){printf("%d ",re[k]);}
		//printf("re \n");
		//printf("%d \n",data_len);
		is_zero = 0;
		for( j = 0 ; j<= (row_end_index-row_start_index);j++){
			is_zero |= data[j];
		//	printf("%d   ",data[j]);
		//	if((j+1)%16==0)printf("\n");
		}
		if(is_zero == 0){
		//	printf("all input is zero\n");
			break;
		};
	}
    return re;
}


void mlp_pre(uint8_t*img){
		printf("\n**********show img*******************\n");
	     for(int i=0*I1;i<I1*1;i++){
				printf("%d",img[i]);
				if((i+1)%22==0){
					printf("\n");
				}
			}
/*
		int16_t out_re1[128] = {0};

		//**********************1. nice input config*******************
	    uint32_t push_row_index,push_data_num,save_index,save_num;
		uint32_t mvm_row_start,mvm_row_end,mvm_col_start,mvm_col_end;
	    push_row_index = 16*0;  // x16
	    push_data_num = 16*36;  // x16
	    save_index = 0;		// x2
	    save_num = 128;     // x2
	    mvm_row_start = 0;
	    mvm_row_end   = 484-1;
	    mvm_col_start = 0;
	    mvm_col_end   = 118-1;
	    uint32_t push_rs2,save_rs2,mvm_rs1,mvm_rs2;
	    push_rs2  = push_row_index << 11| push_data_num;
	    save_rs2  = save_index<< 11 	| save_num;
	    mvm_rs1   = mvm_row_end<< 16 | mvm_col_end;
	    mvm_rs2   = mvm_row_start<<11 	| mvm_col_start;
		//***********************2. first layer input data********************
	    printf("first layer  : \n");
	    uint16_t data_1152[72] = {0};
	    unsigned int begin_cycle,tmp_cycle;
	    begin_cycle = __get_rv_cycle();
	    for(int i = 0 ;i < I1 ;i++){
			//if(	 img1[i]==1){data_1152[i%72]  |=  (uint16_t)1<<(i/72);}
			if(	 img[i]==1) {data_1152[i/8] |= (uint16_t)1<<((i%8)<<1);}
			else{continue;}
		}
	    tmp_cycle = __get_rv_cycle() - begin_cycle;
	    printf("cycle: %d \n" ,tmp_cycle);

	    begin_cycle = __get_rv_cycle();
	    NICE_push((int)data_1152 ,push_rs2);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
		printf("cycle: %d \n" ,tmp_cycle);

		begin_cycle = __get_rv_cycle();
		NICE_mvm(mvm_rs1,mvm_rs2);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
		printf("cycle: %d \n" ,tmp_cycle);

		begin_cycle = __get_rv_cycle();
		NICE_save((int)out_re1,save_rs2);
		tmp_cycle = __get_rv_cycle() - begin_cycle;
		printf("cycle: %d \n" ,tmp_cycle);


		//printf("%8x \n",tmp_re);
		for(int i= 0;i<10;i++){
			printf("%6d",out_re1[i]);
			//	if( (i+1)%16==0 ) printf("\n");
		}
		//*********************3.relu**********************************
		printf("\nbegin relu   : ");
		for(int i= 0;i<128;i++){
			if(out_re1[i]<0) {
	//			printf("%d   ",out_re1[i]);
				out_re1[i]=0;
			}
			if(i<10){
				printf("%6d",out_re1[i] );
			}
		}
		printf("\nsecond layer : ");
		//*********************4. second layer input data**************
		int16_t *out_re2 ;
		out_re2 = matmul(out_re1,128,1,0,118,117,127);
		//*********************5. softmax ****************************
		int max=-65535;
		uint8_t max_index;
		for(int i = 0 ;i <10;i++){
			if(out_re2[i]>max){
				max = out_re2[i];
				max_index = i;
			}
			printf("%6d",out_re2[i]);
		}
		printf("\npredict num = %d\n",max_index);

*/
}



